﻿using System;
using System.Runtime.InteropServices;
using Microsoft.Win32;

namespace ShellExtension
{
    using System.IO;

    internal class Const
    {
        public const int S_OK = 0;
        public const int S_FALSE = 1;
        public const int E_FAIL = -2147467259;
    }

    internal class FileAttribute
    {
        public const int FILE_ATTRIBUTE_READONLY = 0x00000001;
        public const int FILE_ATTRIBUTE_HIDDEN = 0x00000002;
        public const int FILE_ATTRIBUTE_SYSTEM = 0x00000004;
        public const int FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
        public const int FILE_ATTRIBUTE_ARCHIVE = 0x00000020;
        public const int FILE_ATTRIBUTE_DEVICE = 0x00000040;
        public const int FILE_ATTRIBUTE_NORMAL = 0x00000080;
        public const int FILE_ATTRIBUTE_TEMPORARY = 0x00000100;
        public const int FILE_ATTRIBUTE_SPARSE_FILE = 0x00000200;
        public const int FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400;
        public const int FILE_ATTRIBUTE_COMPRESSED = 0x00000800;
        public const int FILE_ATTRIBUTE_OFFLINE = 0x00001000;
        public const int FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000;
        public const int FILE_ATTRIBUTE_ENCRYPTED = 0x00004000;
    }

    public sealed class ShellInterop
    {


        private ShellInterop()
        {
        }

        /*
        * void SHChangeNotify(
        * LONG wEventId,
        * UINT uFlags,
        * LPCVOID dwItem1,
        * LPCVOID dwItem2);
        */
        [DllImport("shell32.dll")]
        public static extern void SHChangeNotify(
        int eventID,
        uint flags,
        IntPtr item1,
        IntPtr item2);

    }

    [ComVisible(false)]
    [ComImport]
    [Guid("0C6C4200-C589-11D0-999A-00C04FD655E1")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IShellIconOverlayIdentifier
    {

        [PreserveSig]
        int IsMemberOf(
            [MarshalAs(UnmanagedType.LPWStr)] string path,

            uint attributes);

        [PreserveSig]
        int GetOverlayInfo(
            IntPtr iconFileBuffer,
            int iconFileBufferSize,
            out int iconIndex,
            out uint flags);

        [PreserveSig]
        int GetPriority(
            out int priority);

    }

    [ComVisible(true)]
    [Guid("B8FA9E43-38E6-4654-8A13-FF905AD22CE5")]
    public class MyIconOverlay : IShellIconOverlayIdentifier
    {

        #region IShellIconOverlayIdentifier Members

        public int IsMemberOf(string path, uint attributes)
        {

            /*System.IO.StreamWriter SW = File.AppendText(@"C:\ov.log");
            SW.WriteLine(path + ":" + attributes);
            SW.Flush();
            SW.Close();*/
            //Show everything with icon overlay
             // S_OK
            try
            {
                if ((attributes & FileAttribute.FILE_ATTRIBUTE_ARCHIVE)>0)
                {
                    return Const.S_OK;
                }
                return Const.S_FALSE;
            }
            catch (Exception)
            {
                return Const.E_FAIL;
            }
        }

        public int GetOverlayInfo( IntPtr iconFileBuffer, int iconFileBufferSize, out int iconIndex, out uint flags)
        {
            System.IO.StreamWriter SW = File.AppendText(@"C:\ov.log");
            SW.WriteLine("getinfo");
            SW.Flush();
            SW.Close();

            System.Diagnostics.Debug.WriteLine(string.Format(" GetOverlayInfo::{0}",iconFileBuffer));

            System.Diagnostics.Debug.WriteLine(string.Format(" GetOverlayInfo::{0}",iconFileBufferSize));
            string fname = @"c:\overlay.ico";

            int bytesCount = System.Text.Encoding.Unicode.GetByteCount(fname);


            System.Diagnostics.Debug.WriteLine(string.Format(" GetOverlayInfo::{0}",bytesCount));

            byte[] bytes = System.Text.Encoding.Unicode.GetBytes(fname);

            if (bytes.Length + 2 < iconFileBufferSize)
            {
                for(int i = 0; i < bytes.Length; i++)
                {
                    Marshal.WriteByte(iconFileBuffer,i,bytes[i]);
                }
                //write the "\0\0" 
                Marshal.WriteByte(iconFileBuffer,bytes.Length,0);
                Marshal.WriteByte(iconFileBuffer,bytes.Length+1,0) ;
            }

            iconIndex = 0;
            flags = 1; // ISIOI_ICONFILE
            return 0; // S_OK
        }


        public int GetPriority(out int priority)
        {
            priority = 0; // 0-100 (0 is highest priority)
            return 0; // S_OK
        }

        public MyIconOverlay()
        {
            System.IO.StreamWriter SW = File.AppendText(@"C:\ov.log");
            SW.WriteLine("ctor");
            SW.Flush();
            SW.Close();
        }

        #endregion

        #region Registry

        [ComRegisterFunction]
        public static void Register(Type t)
        {
            RegistryKey rk =
            Registry.LocalMachine.CreateSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\_" + t.Name);
            rk.SetValue(string.Empty, t.GUID.ToString("B").ToUpper());
            rk.Close();
            ShellInterop.SHChangeNotify(0x08000000, 0, IntPtr.Zero,
            IntPtr.Zero);
        }

        [ComUnregisterFunction]
        public static void Unregister(Type t)
        {

            Registry.LocalMachine.DeleteSubKeyTree(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\_" + t.Name);
            ShellInterop.SHChangeNotify(0x08000000, 0, IntPtr.Zero,
            IntPtr.Zero);
        }

        #endregion

    }

}
